﻿/*
#-------------------------------------------------------------------------------
# Name:        Main Form - the heart of the GUI and starts the LPR
#
# Usage:       This form will be documented in a read me file
# 
#
# Requires:    Visual Studio 2010 and up.
#
# Author:      Roy Scheefhals and Martijn Koopman 
#
# Created:     03-03-2012
#-------------------------------------------------------------------------------
*/


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using LibraryCS;
using System.IO;

namespace Eindproject
{
    public partial class MainForm : Form
    {
        // All the high-res bitmaps shown in the UI
        private List<Bitmap> inputBitmaps = new List<Bitmap>();
        private List<Bitmap> resultBitmaps = new List<Bitmap>();

        private List<LicensePlate> XMLLicensePlates = new List<LicensePlate>();

        // All the vision algorithms to execute
        private List<VisionAlgorithm> visionAlgorithms = new List<VisionAlgorithm>();

        Stopwatch lprStopwatch = new Stopwatch(); // overall LPR stopwatch 

        int numDigits;
        int numLP;
        int numDigLP;

        public MainForm()
        {
            InitializeComponent();

            // Add algorithms to algorithm list
            visionAlgorithms.Add(new MedianExecute("Median Noise Filter"));
            visionAlgorithms.Add(new HSVColorSegmentation("HSV Based Segmentation"));
            visionAlgorithms.Add(new Binarize("Binarize"));
            visionAlgorithms.Add(new NonRecursiveGrowingSelection("License Plate Blob Detection"));
            visionAlgorithms.Add(new SegmentationAlgorithm("Character Segmentation"));
            visionAlgorithms.Add(new OCRAlgorithm("Character Recognition (OCR)"));
        }


        /* *********************************************************** */
        /* ******************** ToolStrip actions ******************** */
        /* *********************************************************** */
        private void openFileToolStripMenuItem_Click(object sender, EventArgs e) {
            // Show open file dialog
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.Filter = "Image Files(*.BMP;*.JPG;*.JPEG;*.PNG;)|*.BMP;*.JPG;*.JPEG;*.PNG;";
            openFileDialog.FilterIndex = 1;
            if (openFileDialog.ShowDialog() == DialogResult.OK) {
                // Open bitmap
                Bitmap openedBitmap = new Bitmap(openFileDialog.FileName);
                FileInfo openedFileInfo = new FileInfo(openFileDialog.FileName);
                openedBitmap.Tag = openedFileInfo.Name;
                // Add bitmap to list
                this.addInputBitmap(openedBitmap, "original", "Original");

                // Show image in resultPictureBox
                resultPictureBox.Image = inputBitmaps[inputBitmaps.Count-1];
            }
        }

        private void openDirectoryToolStripMenuItem_Click(object sender, EventArgs e) {
            // Show folder browser dialog
            FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();
            if (folderBrowserDialog.ShowDialog() == DialogResult.OK) {
                // Get directory path
                string directorypath = folderBrowserDialog.SelectedPath;
                this.log("Opening directory: " + directorypath);

                // Open bitmaps from directory
                string[] supportedFileExtensions = new String[] { "*.BMP", "*.JPG", "*.JPEG", "*.PNG" };
                foreach (string supportedFileExtension in supportedFileExtensions) {
                    // Open files with extension
                    string[] filePaths = Directory.GetFiles(directorypath, supportedFileExtension);
                    foreach (string filePath in filePaths) {
                        this.log("Opening bitmap: " + filePath);

                        // Open bitmap
                        Bitmap openedBitmap = new Bitmap(filePath);
                        ;
                        FileInfo openedFileInfo = new FileInfo(filePath);
                        openedBitmap.Tag = openedFileInfo.Name;
                        string[] filePathPieces = filePath.Split(new char[] { '\\' });

                        // Add bitmap to list
                        this.addInputBitmap(openedBitmap, 
                            filePathPieces[filePathPieces.Length-1],
                            filePathPieces[filePathPieces.Length-1]);

                        // Show image in resultPictureBox
                        resultPictureBox.Image = inputBitmaps[0];
                    }
                }
            }
        }

        private void closeToolStripMenuItem_Click(object sender, EventArgs e) {
            // Remove image from resultPictureBox
            resultPictureBox.Image = null;

            // Clear input bitmaps list
            inputListView.Items.Clear();
            inputImageList.Images.Clear();
            inputBitmaps.Clear();

            // Clear result Bitmaps list
            resultListView.Items.Clear();
            resultImageList.Images.Clear();
            resultBitmaps.Clear();

            // Clear logTextBox
            logTextBox.Text = "";
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e) {
            if (resultPictureBox.Image != null) {
                // Show save file dialog
                SaveFileDialog saveFileDialog = new SaveFileDialog();
                saveFileDialog.Filter = "Image Files(*.BMP;*.JPG;*.JPEG;*.PNG;)|*.BMP;*.JPG;*.JPEG;*.PNG;";
                saveFileDialog.FilterIndex = 1;
                if (saveFileDialog.ShowDialog() == DialogResult.OK) {
                    // Get filenames
                    resultPictureBox.Image.Save(saveFileDialog.FileName);
                }
            }
        }

        private void saveAllToolStripMenuItem_Click(object sender, EventArgs e) {

        }

        private void clearToolStripMenuItem_Click(object sender, EventArgs e) {
            // Remove image from resultPictureBox
            resultPictureBox.Image = null;

            // Clear result Bitmaps list
            resultListView.Items.Clear();
            resultImageList.Images.Clear();
            resultBitmaps.Clear();

            // Clear logTextBox
            logTextBox.Text = "";
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e) {
            Application.Exit();
        }


        /* ********************************************************** */
        /* ******************** Other UI actions ******************** */
        /* ********************************************************** */
        // bitmap selected from list
        private void inputListView_SelectedIndexChanged(object sender, EventArgs e) {
            // Get index of selected image
            if (inputListView.SelectedItems.Count > 0) {
                int bitmapIndex = inputListView.SelectedItems[0].Index;
                // Show image corresponding to selected in resultPictureBox
                resultPictureBox.Image = inputBitmaps[bitmapIndex];
            }
        }

        // bitmap selected from list
        private void resultListView_SelectedIndexChanged(object sender, EventArgs e) {
            // Get index of selected image
            if (resultListView.SelectedItems.Count > 0) {
                int bitmapIndex = resultListView.SelectedItems[0].Index;
                // Show image corresponding to selected in resultPictureBox
                resultPictureBox.Image = resultBitmaps[bitmapIndex];
            }
        }

        // 'Settings' button clicked
        private void settingsButton_Click(object sender, EventArgs e) {
            SettingsForm settingsForm = new SettingsForm(visionAlgorithms);
            settingsForm.Show();
        }

        // 'Start' button clicked
        private void startButton_Click(object sender, EventArgs e) {
            // check for verbose mode
            bool verbose = verboseCheckBox.Checked;

            // Try to get the input bitmap
            if (inputBitmaps.Count > 0) {
                // create arguments list
                List<object> arguments = new List<object>();
                arguments.Add(visionAlgorithms);
                arguments.Add(inputBitmaps);
                arguments.Add(verbose);

                //disable startbutton ( monkey proofing ) 
                startButton.Enabled = false;
                verboseCheckBox.Enabled = false;
                settingsButton.Enabled = false;
                compareCheckBox.Enabled = false;
                loadXmlButton.Enabled = false;
                // Start License Plate Recognition (LPR)
                lprBackgroundWorker.RunWorkerAsync(arguments);

            } else {
                // No input image specified (show error message)
                MessageBox.Show("No image specified", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void compareCheckBox_CheckedChanged(object sender, EventArgs e) {
            if(compareCheckBox.Checked) {
                inputGroupBox.Enabled = true;
                outputGroupBox.Enabled = true;
            } else {
               inputGroupBox.Enabled = false;
               outputGroupBox.Enabled = false;
            }
        }


        /* *************************************************************** */
        /* ********** Execute Licecense Plate Recognition (LPR) ********** */
        /* *************************************************************** */
        private void lprBackgroundWorker_DoWork(object sender, DoWorkEventArgs e) {

            numDigits = 0;
            numDigLP = 0;
            numLP = 0;

            List<object> arguments = e.Argument as List<object>;
            List<VisionAlgorithm> VisionAlgorithms = (List<VisionAlgorithm>)arguments[0];
            List<Bitmap> bitmapsToProcess= new List<Bitmap>((List<Bitmap>)arguments[1]);
            bool verbose = (bool)arguments[2];

            LicensePlateRecognition LPR = new LicensePlateRecognition(VisionAlgorithms, lprBackgroundWorker, verbose);

            lprBackgroundWorker.ReportProgress(0, "\n\nLicense Plate Recognition (LPR) started " +
                            "(verbose = " + (verbose ? "on" : "off") + ")");

            List<LicensePlate> foundLPNs = new List<LicensePlate>();

            // Start overall stopwatch
            lprStopwatch.Reset();
            lprStopwatch.Start();

            Stopwatch singleLPStopwatch = new Stopwatch();
            
            foreach (Bitmap inputBitmap in bitmapsToProcess)
            {
                // Do Licensce Plate Recognition
                

                singleLPStopwatch.Reset();
                singleLPStopwatch.Start();
                List<LicensePlate> currentFoundLPNs =LPR.doLPR(inputBitmap);
                singleLPStopwatch.Stop();
                String logResult = "" ;
                foreach (LicensePlate LP in currentFoundLPNs)
                {
                    LP.filename = (string)inputBitmap.Tag;
                    logResult += "License Plate Found : " + LP.text + "\n\n";
                }
                lprBackgroundWorker.ReportProgress(0, logResult + "LPR took: " + singleLPStopwatch.ElapsedMilliseconds+ "\n");
                foundLPNs.AddRange(currentFoundLPNs);
            }

            // Stop overall stopwatch
            lprStopwatch.Stop();

            // Set found license plate numbers as result
            e.Result = foundLPNs;
        }

        private void lprBackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) {
            int progressId = e.ProgressPercentage;

            switch(progressId) {
                case 0: // Log
                    String message = (String)e.UserState;
                    this.log(message);
                    break;
                case 1: // Output result bitmap
                    List<object> arguments = (List<object>)e.UserState;
                    Bitmap resultBitmap = (Bitmap)arguments[0];
                    string name = (string)arguments[1];
                    addResultBitmap(resultBitmap, name, name);
                    break;
            }
        }

        private void lprBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
            // Print overall elapsed time
            this.log("LPR took " + lprStopwatch.ElapsedMilliseconds + "ms");

            // Get found license plate numbers
            List<LicensePlate> foundLPNs = (List<LicensePlate>)e.Result;

            // Print found license plate numbers
            if (foundLPNs.Count > 0) {
                log("\nFound " + foundLPNs.Count + " license plate number(s)!\n");
                foreach (LicensePlate foundLPN in foundLPNs) {
                    log(foundLPN.ToString());
                }
            } else {
                log("No license plate number(s) found!");
            }

            if (compareCheckBox.Checked)
            {
                if (XMLLicensePlates.Count <= 0)
                {
                    MessageBox.Show("Error, the are no Licenseplates loaded from XML File.\nPlease load new XML file and redo Recognition", "error comparing", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                }
                else
                {
                    foreach (LicensePlate LP in foundLPNs)
                    {
                        string FilenameToFind = LP.filename;
                        LicensePlate XMLLP = XMLLicensePlates.Find(delegate(LicensePlate XMLLPtemp) { return XMLLPtemp.filename == FilenameToFind; });
     //                   Debug.WriteLine("asdfasdfasdf: " + XMLLP+ " : " + result);
                        if (XMLLP != null)
                        {
                            double result =  XMLLP.compareLocation(LP);
                            int resultDigits = XMLLP.compareText(LP);

                            Debug.WriteLine("result: " + FilenameToFind + " : " +result);

                            if (result > 60.0)
                                numLP++;
                            numDigits += resultDigits;
                            if (resultDigits == 6 && result > 60.0)
                            {
                                numDigLP++;
                            }
                        }
                    }

                    numLocatedLPs.Text = ""+numLP.ToString();
                    numIdentifiedDigits.Text = ""+ numDigits.ToString();
                    numberIdentifiedFullPlates.Text = ""+ numDigLP.ToString();
                }
            }

            // enable the startbutton again after bg worker is complete
            startButton.Enabled = true;
            verboseCheckBox.Enabled = true;
            settingsButton.Enabled = true;
            compareCheckBox.Enabled = true;
            loadXmlButton.Enabled = true;
        }


        /* ********************************************** */
        /* ******************** Util ******************** */
        /* ********************************************** */
        // Add bitmap to input list
        private void addInputBitmap(Bitmap inputBitmap, string identifier, string name) {
            // Add bitmap to result bitmaps list
            inputBitmaps.Add(inputBitmap);
            inputImageList.Images.Add(inputBitmap);
            inputListView.Items.Add(identifier, name, inputImageList.Images.Count - 1);
        }

        // Add bitmap to result list
        private void addResultBitmap(Bitmap resultBitmap, string identifier, string name) {
            if (resultBitmap != null) {
                // Add bitmap to result bitmaps list
                resultBitmaps.Add(resultBitmap);
                resultImageList.Images.Add(resultBitmap);
                resultListView.Items.Add(identifier, name, resultImageList.Images.Count - 1);
            }
        }

        // Print log message in console
        private void log(string message) {
            logTextBox.Text += message + "\n";
        }

        private void loadXmlButton_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "*.xml|*.xml";
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                XMLreader reader = new XMLreader();
                XMLLicensePlates = reader.readXML(ofd.FileName);
                XMLItemsLabel.Text = "" + XMLLicensePlates.Count;
                XMLLoadTextBox.Text = ofd.FileName;
            }
        }
    }
}
